<template>
  <div class="h-full flex flex-col bg-gray-50" v-loading="isStoppingDebugger" element-loading-text="正在停止调试器..." element-loading-background="rgba(0, 0, 0, 0.7)">
    <!-- dlv状态栏 -->
    <dlv-status />

    <!-- 顶部工具栏 -->
    <div class="bg-white border-b border-gray-200 px-5 py-4 flex-shrink-0">
      <div class="flex items-center justify-between">
        <div class="flex items-center gap-3">
          <img src="/icon.svg" alt="GuLu logo" class="w-8 h-8" />
          <h2 class="m-0 text-gray-800 text-lg font-medium">GuLu - Go程序调试</h2>
        </div>
        <div class="flex items-center gap-4">
          <el-button
            type="primary"
            icon="el-icon-folder-opened"
            size="small"
            @click="selectProgram"
          >
            选择程序
          </el-button>
          <span
            v-if="programPath"
            class="text-gray-500 text-xs max-w-[300px] overflow-hidden text-ellipsis whitespace-nowrap"
            :title="programPath"
          >
            {{ formatProgramPath(programPath) }}
          </span>
        </div>
      </div>
    </div>

    <!-- 调试内容区 -->
    <div class="flex-1 overflow-hidden p-3 gap-3 flex">
      <!-- 左侧面板：断点和堆栈 -->
      <div :style="{width: leftPanelWidth}" class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden relative flex-shrink-0">
        <div class="absolute top-0 bottom-0 right-0 w-1 cursor-col-resize z-10 transition-colors hover:bg-primary-500" @mousedown="startResize('left', $event)"></div>
        <el-tabs v-model="leftActiveTab" class="h-full side-tabs">
          <el-tab-pane label="断点" name="breakpoints">
            <breakpoint-panel
              ref="breakpointPanel"
              :breakpoints="breakpoints"
              :debugger-state="debuggerState"
              :sources="sources"
              :sources-loading="sourcesLoading"
              @add="handleAddBreakpoint"
              @edit="handleEditBreakpoint"
              @remove="handleRemoveBreakpoint"
              @toggle="handleToggleBreakpoint"
              @batch-toggle="handleBatchToggleBreakpoint"
              @batch-remove="handleBatchRemoveBreakpoint"
              @import="handleImportBreakpoints"
            />
          </el-tab-pane>
          <el-tab-pane label="调用堆栈" name="stack">
            <stacktrace-panel
              :frames="stackFrames"
              :loading="stackLoading"
              @refresh="refreshStack"
            />
          </el-tab-pane>
          <el-tab-pane label="Goroutine" name="goroutines">
            <goroutine-panel
              :goroutines="goroutines"
              :loading="goroutinesLoading"
              :selected-goroutine-id="selectedGoroutineId"
              @refresh="refreshGoroutines"
              @select="handleSelectGoroutine"
            />
          </el-tab-pane>
        </el-tabs>
      </div>

      <!-- 主内容区 -->
      <div class="flex-1 overflow-hidden flex flex-col gap-3">
        <!-- 调试控制面板 -->
        <div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
          <debug-control-panel
            :debugger-state="debuggerState"
            :is-running="isRunning"
            :is-paused="isPaused"
            @start="handleStart"
            @stop="handleStop"
            @continue="handleContinue"
            @step-over="handleStepOver"
            @step-into="handleStepInto"
            @step-out="handleStepOut"
          />
        </div>

        <!-- 调试输出日志 -->
        <div class="flex-1 overflow-hidden bg-white rounded-lg shadow-sm border border-gray-200">
          <output-panel
            :logs="outputLogs"
            @clear="handleClearLogs"
          />
        </div>
      </div>

      <!-- 右侧面板：变量监视和Watch -->
      <div :style="{width: rightPanelWidth}" class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden relative flex-shrink-0">
        <div class="absolute top-0 bottom-0 left-0 w-1 cursor-col-resize z-10 transition-colors hover:bg-primary-500" @mousedown="startResize('right', $event)"></div>
        <el-tabs v-model="rightActiveTab" class="h-full side-tabs">
          <el-tab-pane label="变量" name="variables">
            <variable-panel
              ref="variablePanel"
              :local-variables="localVariables"
              :loading="variablesLoading"
              @refresh="refreshVariables"
              @evaluate="handleEvaluate"
            />
          </el-tab-pane>
          <el-tab-pane label="Watch" name="watch">
            <watch-panel
              :watches="watchExpressions"
              :loading="watchLoading"
              @add="handleAddWatch"
              @remove="handleRemoveWatch"
              @refresh="refreshWatches"
            />
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>
  </div>
</template>

<script>
import DlvStatus from '../components/DlvStatus.vue'
import DebugControlPanel from '../components/DebugControlPanel.vue'
import BreakpointPanel from '../components/BreakpointPanel.vue'
import StacktracePanel from '../components/StacktracePanel.vue'
import VariablePanel from '../components/VariablePanel.vue'
import OutputPanel from '../components/OutputPanel.vue'
import WatchPanel from '../components/WatchPanel.vue'
import GoroutinePanel from '../components/GoroutinePanel.vue'
import debuggerApi from '../api/debugger'

export default {
  name: 'DebuggerView',
  components: {
    DlvStatus,
    DebugControlPanel,
    BreakpointPanel,
    StacktracePanel,
    VariablePanel,
    OutputPanel,
    WatchPanel,
    GoroutinePanel
  },
  provide() {
    return {
      getCurrentGoroutineId: () => this.currentGoroutineId || -1,
      getCurrentFrameIndex: () => 0, // 当前固定使用栈帧 0
      setVariableValue: this.setVariableValue
    }
  },
  data() {
    return {
      programPath: '',
      lastProgramPath: '', // 记录上次调试的程序路径
      debuggerState: 'stopped',
      isStoppingDebugger: false, // 停止调试器的 loading 状态
      leftActiveTab: 'breakpoints',
      rightActiveTab: 'variables',
      breakpoints: [],
      stackFrames: [],
      stackLoading: false,
      localVariables: [],
      variablesLoading: false,
      watchExpressions: [],
      watchLoading: false,
      goroutines: [],
      goroutinesLoading: false,
      selectedGoroutineId: null,
      currentGoroutineId: null, // 当前断点所在的 goroutine ID
      outputLogs: [],
      pendingLogs: [], // 待添加的日志缓冲区
      maxLogCount: 1000, // 最大日志条数
      leftPanelWidth: '320px',
      rightPanelWidth: '320px',
      resizing: false,
      resizePanel: null,
      // 变量加载深度配置
      localVariableDepth: 3,
      // 源文件列表
      sources: [],
      sourcesLoading: false
    }
  },
  computed: {
    isRunning() {
      return this.debuggerState === 'running'
    },
    isPaused() {
      return this.debuggerState === 'paused'
    }
  },
  mounted() {
    this.loadSettings()
    this.setupDebuggerListeners()
    this.setupEventListeners()
  },
  beforeDestroy() {
    // 清理定时器
    if (this._refreshVariablesTimer) {
      clearTimeout(this._refreshVariablesTimer)
    }
    if (this._flushLogsTimer) {
      clearTimeout(this._flushLogsTimer)
      this.flushPendingLogs() // 清理前刷新剩余日志
    }
    // 清理数据
    this.clearDebugInfo()
    // 清理事件监听
    this.$root.$off('load-program', this.handleLoadProgram)
    this.$root.$off('debug-program', this.handleDebugProgramFromHistory)
  },
  methods: {
    // 加载设置
    loadSettings() {
      try {
        const savedSettings = localStorage.getItem('debugger-settings')
        if (savedSettings) {
          const settings = JSON.parse(savedSettings)
          this.localVariableDepth = settings.localVariableDepth || 3
        }
      } catch (error) {
        console.error('加载设置失败:', error)
      }
    },

    // 保存到历史记录
    async saveToHistory(programPath) {
      try {
        // 获取现有历史记录
        const result = await debuggerApi.loadHistory()
        let history = result.data || []

        // 检查是否已存在
        const existingIndex = history.findIndex(item => item.path === programPath)

        if (existingIndex !== -1) {
          // 已存在，更新最后使用时间并移到最前面
          history.splice(existingIndex, 1)
        }

        // 准备断点数据（移除 dlvId，只保存用户定义的断点信息）
        const breakpointsToSave = this.breakpoints.map(bp => ({
          id: bp.id,
          file: bp.file,
          line: bp.line,
          condition: bp.condition || null,
          hitCondition: bp.hitCondition || null
        }))

        // 添加到历史记录开头
        history.unshift({
          path: programPath,
          lastUsed: new Date().toISOString(),
          name: this.extractProgramName(programPath),
          breakpoints: breakpointsToSave // 保存断点列表
        })

        // 限制历史记录数量（最多保留20条）
        if (history.length > 20) {
          history = history.slice(0, 20)
        }

        // 保存到文件
        await debuggerApi.saveHistory(history)
      } catch (error) {
        console.error('保存历史记录失败:', error)
      }
    },

    // 提取程序名称
    extractProgramName(path) {
      if (!path) return ''
      const parts = path.split(/[/\\]/)
      return parts[parts.length - 1]
    },

    // 格式化程序路径显示
    formatProgramPath(path) {
      if (!path) return ''
      const parts = path.split(/[/\\]/)
      if (parts.length > 3) {
        return '...' + parts.slice(-3).join('/')
      }
      return parts.join('/')
    },

    // 选择程序
    async selectProgram() {
      const result = await debuggerApi.selectFile()
      if (!result.canceled) {
        const newPath = result.filePath

        // 如果切换了程序，清空断点、源文件列表和输出日志
        if (this.programPath && this.programPath !== newPath) {
          this.breakpoints = []
          this.outputLogs = [] // 清空调试输出日志
          this.sources = [] // 清空源文件列表
          this.$message.info('已切换程序，断点和日志已清空')
        }

        this.programPath = newPath
        this.$message.success('已选择程序')
      }
    },

    // 启动调试
    async handleStart() {
      if (!this.programPath) {
        this.$message.warning('请先选择要调试的程序')
        return
      }

      // 清空上一次调试的输出日志
      this.outputLogs = []

      try {
        const result = await debuggerApi.startDebugger(this.programPath, [])
        if (result.success) {
          this.debuggerState = 'paused'
          this.$message.success('调试器启动成功')

          // 记录当前程序路径
          this.lastProgramPath = this.programPath

          // 保存到历史记录
          this.saveToHistory(this.programPath)

          // 加载源文件列表（一次性加载）
          await this.loadSourceFiles()

          // 恢复之前的断点
          await this.restoreBreakpoints()

          // 等待 dlv 完全准备好，让程序进入 main 函数
          await new Promise(resolve => setTimeout(resolve, 300))

          // 再次确认状态仍然是 paused
          if (this.debuggerState === 'paused') {
            await this.refreshAll()
          }
        } else {
          this.$message.error('启动失败：' + result.message)
        }
      } catch (error) {
        this.$message.error('启动失败：' + error.message)
      }
    },

    // 停止调试
    async handleStop() {
      // 显示全屏 loading
      this.isStoppingDebugger = true
      this.debuggerState = 'stopping'

      try {
        const result = await debuggerApi.stopDebugger()

        if (result.success) {
          this.debuggerState = 'stopped'
          this.$message.success('调试器已停止')

          // 保存历史记录（包含断点）
          if (this.lastProgramPath) {
            this.saveToHistory(this.lastProgramPath)
          }

          this.clearDebugInfo()
          // 清空源文件列表，以便下次启动时重新加载
          this.sources = []
          // 注意：不清空 breakpoints，保留断点列表供下次使用
        } else {
          this.debuggerState = 'stopped'
          this.$message.error('停止失败：' + result.message)
        }
      } catch (error) {
        this.debuggerState = 'stopped'
        this.$message.error('停止失败：' + error.message)
      } finally {
        // 关闭全屏 loading
        this.isStoppingDebugger = false
      }
    },

    // 继续执行
    async handleContinue() {
      try {
        // 清除变量刷新的定时器，防止竞态条件
        if (this._refreshVariablesTimer) {
          clearTimeout(this._refreshVariablesTimer)
          this._refreshVariablesTimer = null
        }

        const result = await debuggerApi.continue()

        if (result.success) {
          this.debuggerState = 'running'
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('操作失败：' + error.message)
      }
    },


    // 单步执行（步过）
    async handleStepOver() {
      try {
        const result = await debuggerApi.stepOver()
        if (result.success) {
          this.debuggerState = 'paused'
          await this.refreshAll()
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('操作失败：' + error.message)
      }
    },

    // 单步执行（步入）
    async handleStepInto() {
      try {
        const result = await debuggerApi.stepInto()
        if (result.success) {
          this.debuggerState = 'paused'
          await this.refreshAll()
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('操作失败：' + error.message)
      }
    },

    // 单步执行（步出）
    async handleStepOut() {
      try {
        const result = await debuggerApi.stepOut()
        if (result.success) {
          this.debuggerState = 'paused'
          await this.refreshAll()
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('操作失败：' + error.message)
      }
    },

    // 添加断点
    async handleAddBreakpoint(breakpoint) {
      // 如果调试器未运行，只添加到列表，不调用API
      if (this.debuggerState === 'stopped') {
        this.breakpoints.push({
          id: Date.now(),
          file: breakpoint.file,
          line: breakpoint.line,
          condition: breakpoint.condition || null,
          hitCondition: breakpoint.hitCondition || null,
          enabled: true, // 默认启用
          dlvId: null, // 标记为未设置到dlv
          hitCount: 0 // 初始化命中次数
        })
        this.$message.success('断点已添加（将在启动调试时生效）')
        return
      }

      // 如果调试器正在运行，立即设置断点
      try {
        const result = await debuggerApi.setBreakpoint(
          breakpoint.file,
          breakpoint.line,
          breakpoint.condition,
          breakpoint.hitCondition
        )
        if (result.success) {
          this.breakpoints.push({
            ...result.breakpoint,
            enabled: true, // 默认启用
            hitCount: 0 // 初始化命中次数
          })
          this.$message.success('断点已添加')
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('添加断点失败：' + error.message)
      }
    },

    // 编辑断点
    async handleEditBreakpoint(data) {
      const { id, file, line, condition, hitCondition } = data
      const breakpoint = this.breakpoints.find(bp => bp.id === id)

      if (!breakpoint) {
        this.$message.error('断点不存在')
        return
      }

      // 如果调试器未运行，直接更新列表
      if (this.debuggerState === 'stopped' || breakpoint.dlvId === null) {
        breakpoint.file = file
        breakpoint.line = line
        breakpoint.condition = condition
        breakpoint.hitCondition = hitCondition
        this.$message.success('断点已更新')
        return
      }

      // 如果调试器正在运行，需要先删除旧断点，再创建新断点
      try {
        // 删除旧断点
        const deleteResult = await debuggerApi.clearBreakpoint(id)
        if (!deleteResult.success) {
          this.$message.error('更新断点失败：' + deleteResult.message)
          return
        }

        // 创建新断点
        const createResult = await debuggerApi.setBreakpoint(file, line, condition, hitCondition)
        if (createResult.success) {
          // 更新断点数据（保持原有ID，但更新dlvId和其他字段）
          breakpoint.file = file
          breakpoint.line = line
          breakpoint.condition = condition
          breakpoint.hitCondition = hitCondition
          breakpoint.dlvId = createResult.breakpoint.dlvId
          this.$message.success('断点已更新')
        } else {
          this.$message.error('更新断点失败：' + createResult.message)
          // 如果创建失败，从列表中删除该断点
          this.breakpoints = this.breakpoints.filter(bp => bp.id !== id)
        }
      } catch (error) {
        this.$message.error('更新断点失败：' + error.message)
      }
    },

    // 删除断点
    async handleRemoveBreakpoint(id) {
      const breakpoint = this.breakpoints.find(bp => bp.id === id)

      if (!breakpoint) {
        return
      }

      // 如果调试器已停止，或者断点未设置到dlv，直接从列表删除
      if (this.debuggerState === 'stopped' || breakpoint.dlvId === null) {
        this.breakpoints = this.breakpoints.filter(bp => bp.id !== id)
        this.$message.success('断点已删除')
        return
      }

      // 如果调试器正在运行且断点已设置到dlv，调用API删除
      try {
        const result = await debuggerApi.clearBreakpoint(id)
        if (result.success) {
          this.breakpoints = this.breakpoints.filter(bp => bp.id !== id)
          this.$message.success('断点已删除')
        } else {
          this.$message.error(result.message)
        }
      } catch (error) {
        this.$message.error('删除断点失败：' + error.message)
      }
    },

    // 切换断点启用/禁用状态
    async handleToggleBreakpoint(id) {
      const breakpoint = this.breakpoints.find(bp => bp.id === id)
      if (!breakpoint) return

      const newEnabledState = !breakpoint.enabled

      // 如果调试器未运行，直接切换状态
      if (this.debuggerState === 'stopped') {
        breakpoint.enabled = newEnabledState
        this.$message.success(newEnabledState ? '断点已启用' : '断点已禁用')
        return
      }

      // 如果调试器正在运行
      try {
        if (newEnabledState) {
          // 启用断点：设置到dlv
          const result = await debuggerApi.setBreakpoint(
            breakpoint.file,
            breakpoint.line,
            breakpoint.condition,
            breakpoint.hitCondition
          )
          if (result.success) {
            breakpoint.enabled = true
            breakpoint.dlvId = result.breakpoint.dlvId
            this.$message.success('断点已启用')
          } else {
            this.$message.error('启用失败：' + result.message)
          }
        } else {
          // 禁用断点：从dlv删除
          if (breakpoint.dlvId) {
            const result = await debuggerApi.clearBreakpoint(id)
            if (result.success) {
              breakpoint.enabled = false
              breakpoint.dlvId = null
              this.$message.success('断点已禁用')
            } else {
              this.$message.error('禁用失败：' + result.message)
            }
          } else {
            breakpoint.enabled = false
            this.$message.success('断点已禁用')
          }
        }
      } catch (error) {
        this.$message.error('操作失败：' + error.message)
      }
    },

    // 批量切换断点启用/禁用状态
    async handleBatchToggleBreakpoint({ ids, enabled }) {
      const loading = this.$loading({
        lock: true,
        text: enabled ? '正在批量启用断点...' : '正在批量禁用断点...',
        background: 'rgba(0, 0, 0, 0.7)'
      })

      try {
        let successCount = 0
        let failCount = 0

        for (const id of ids) {
          const breakpoint = this.breakpoints.find(bp => bp.id === id)
          if (!breakpoint) continue

          // 如果调试器未运行，直接切换状态
          if (this.debuggerState === 'stopped') {
            breakpoint.enabled = enabled
            successCount++
            continue
          }

          // 如果调试器正在运行
          try {
            if (enabled) {
              // 启用断点：设置到dlv
              const result = await debuggerApi.setBreakpoint(
                breakpoint.file,
                breakpoint.line,
                breakpoint.condition,
                breakpoint.hitCondition
              )
              if (result.success) {
                breakpoint.enabled = true
                breakpoint.dlvId = result.breakpoint.dlvId
                successCount++
              } else {
                failCount++
              }
            } else {
              // 禁用断点：从dlv删除
              if (breakpoint.dlvId) {
                const result = await debuggerApi.clearBreakpoint(id)
                if (result.success) {
                  breakpoint.enabled = false
                  breakpoint.dlvId = null
                  successCount++
                } else {
                  failCount++
                }
              } else {
                breakpoint.enabled = false
                successCount++
              }
            }
          } catch (error) {
            console.error(`批量操作断点 ${id} 失败:`, error)
            failCount++
          }
        }

        loading.close()

        // 显示结果
        if (failCount === 0) {
          this.$message.success(`成功${enabled ? '启用' : '禁用'}了 ${successCount} 个断点`)
        } else {
          this.$message.warning(`${enabled ? '启用' : '禁用'}了 ${successCount} 个断点，${failCount} 个失败`)
        }
      } catch (error) {
        loading.close()
        this.$message.error('批量操作失败：' + error.message)
      }
    },

    // 批量删除断点
    async handleBatchRemoveBreakpoint(ids) {
      const loading = this.$loading({
        lock: true,
        text: '正在批量删除断点...',
        background: 'rgba(0, 0, 0, 0.7)'
      })

      try {
        let successCount = 0
        let failCount = 0

        for (const id of ids) {
          const breakpoint = this.breakpoints.find(bp => bp.id === id)
          if (!breakpoint) continue

          // 如果调试器已停止，或者断点未设置到dlv，直接从列表删除
          if (this.debuggerState === 'stopped' || breakpoint.dlvId === null) {
            this.breakpoints = this.breakpoints.filter(bp => bp.id !== id)
            successCount++
            continue
          }

          // 如果调试器正在运行且断点已设置到dlv，调用API删除
          try {
            const result = await debuggerApi.clearBreakpoint(id)
            if (result.success) {
              this.breakpoints = this.breakpoints.filter(bp => bp.id !== id)
              successCount++
            } else {
              failCount++
            }
          } catch (error) {
            console.error(`批量删除断点 ${id} 失败:`, error)
            failCount++
          }
        }

        loading.close()

        // 显示结果
        if (failCount === 0) {
          this.$message.success(`成功删除了 ${successCount} 个断点`)
        } else {
          this.$message.warning(`删除了 ${successCount} 个断点，${failCount} 个失败`)
        }
      } catch (error) {
        loading.close()
        this.$message.error('批量删除失败：' + error.message)
      }
    },

    // 导入断点
    async handleImportBreakpoints(importedBreakpoints) {
      const loading = this.$loading({
        lock: true,
        text: '正在导入断点...',
        background: 'rgba(0, 0, 0, 0.7)'
      })

      try {
        let successCount = 0
        let failCount = 0
        let skippedCount = 0

        for (const bp of importedBreakpoints) {
          // 检查是否已存在相同位置的断点（文件 + 行号）
          const exists = this.breakpoints.some(
            existing => existing.file === bp.file && existing.line === bp.line
          )

          if (exists) {
            skippedCount++
            continue
          }

          // 生成新的断点 ID
          const newId = Date.now() + Math.random()

          // 如果调试器未运行，只添加到列表
          if (this.debuggerState === 'stopped') {
            this.breakpoints.push({
              id: newId,
              file: bp.file,
              line: bp.line,
              condition: bp.condition || null,
              hitCondition: bp.hitCondition || null,
              enabled: bp.enabled !== false,
              dlvId: null,
              hitCount: 0
            })
            successCount++
            continue
          }

          // 如果调试器正在运行且断点为启用状态，立即设置到dlv
          if (bp.enabled !== false) {
            try {
              const result = await debuggerApi.setBreakpoint(
                bp.file,
                bp.line,
                bp.condition,
                bp.hitCondition
              )
              if (result.success) {
                this.breakpoints.push({
                  ...result.breakpoint,
                  enabled: true,
                  hitCount: 0
                })
                successCount++
              } else {
                // 设置失败，仍然添加到列表但标记为未设置
                this.breakpoints.push({
                  id: newId,
                  file: bp.file,
                  line: bp.line,
                  condition: bp.condition || null,
                  hitCondition: bp.hitCondition || null,
                  enabled: false,
                  dlvId: null,
                  hitCount: 0
                })
                failCount++
              }
            } catch (error) {
              console.error('导入断点失败:', error)
              failCount++
            }
          } else {
            // 禁用状态的断点直接添加到列表
            this.breakpoints.push({
              id: newId,
              file: bp.file,
              line: bp.line,
              condition: bp.condition || null,
              hitCondition: bp.hitCondition || null,
              enabled: false,
              dlvId: null,
              hitCount: 0
            })
            successCount++
          }
        }

        loading.close()

        // 显示结果
        const messages = []
        if (successCount > 0) {
          messages.push(`成功导入 ${successCount} 个断点`)
        }
        if (skippedCount > 0) {
          messages.push(`跳过 ${skippedCount} 个重复断点`)
        }
        if (failCount > 0) {
          messages.push(`${failCount} 个断点设置失败`)
        }

        if (messages.length > 0) {
          const messageType = failCount > 0 ? 'warning' : 'success'
          this.$message[messageType](messages.join('，'))
        }
      } catch (error) {
        loading.close()
        this.$message.error('导入失败：' + error.message)
      }
    },

    // 刷新调用堆栈
    async refreshStack() {
      if (this.debuggerState !== 'paused') return

      this.stackLoading = true
      try {
        const result = await debuggerApi.getStacktrace(50)
        if (result.success) {
          this.stackFrames = result.frames
        }
      } catch (error) {
        console.error('获取堆栈失败：', error)
      } finally {
        this.stackLoading = false
      }
    },

    // 刷新变量（添加防抖）
    async refreshVariables() {
      if (this.debuggerState !== 'paused') {
        return
      }

      // 防抖：如果正在加载，取消之前的请求
      if (this._refreshVariablesTimer) {
        clearTimeout(this._refreshVariablesTimer)
      }

      this._refreshVariablesTimer = setTimeout(async () => {
        // 再次检查状态，防止在定时器触发前状态已改变
        if (this.debuggerState !== 'paused') {
          return
        }

        this.variablesLoading = true
        try {
          // 先获取最新的 dlv 状态，确保使用正确的 goroutine ID
          const stateResult = await debuggerApi.getState()
          let goroutineID = -1

          if (stateResult.success && stateResult.state) {
            if (stateResult.state.currentGoroutine && stateResult.state.currentGoroutine.id) {
              goroutineID = stateResult.state.currentGoroutine.id
              // 更新缓存的 currentGoroutineId
              this.currentGoroutineId = goroutineID
            } else {
              goroutineID = this.currentGoroutineId || -1
            }
          } else {
            goroutineID = this.currentGoroutineId || -1
          }

          // 再次检查状态，防止在 getState 期间状态已改变
          if (this.debuggerState !== 'paused') {
            return
          }

          // 获取局部变量（使用配置的深度）
          const localResult = await debuggerApi.getLocalVariables(goroutineID, 0, this.localVariableDepth)

          if (localResult.success) {
            this.localVariables = localResult.variables
          } else {
            // 如果是 "unable to find function context" 错误，说明程序还没进入用户代码，不显示错误
            if (!localResult.message.includes('unable to find function context')) {
              console.error('[DebuggerView] 获取局部变量失败:', localResult.message)
            }
            this.localVariables = []
          }
        } catch (error) {
          console.error('[DebuggerView] 获取变量异常：', error)
        } finally {
          this.variablesLoading = false
        }
      }, 100) // 100ms 防抖延迟
    },

    // 求值表达式
    async handleEvaluate(params) {
      // 兼容旧格式（字符串）和新格式（对象）
      const expression = typeof params === 'string' ? params : params.expression
      const maxDepth = typeof params === 'object' ? params.maxDepth : 3

      try {
        const result = await debuggerApi.evaluate(expression, maxDepth)
        if (result.success) {
          // 将结果传递回 VariablePanel 组件，以树形结构显示
          if (this.$refs.variablePanel) {
            this.$refs.variablePanel.evaluateResult = result.variable
            this.$refs.variablePanel.evaluating = false
          }
          this.$message.success('求值成功')
        } else {
          if (this.$refs.variablePanel) {
            this.$refs.variablePanel.evaluating = false
          }
          this.$message.error(result.message)
        }
      } catch (error) {
        if (this.$refs.variablePanel) {
          this.$refs.variablePanel.evaluating = false
        }
        this.$message.error('求值失败：' + error.message)
      }
    },

    // 清空日志
    handleClearLogs() {
      this.outputLogs = []
      this.pendingLogs = []
    },

    // 添加日志到缓冲区（批量处理以提升性能）
    addLog(log) {
      this.pendingLogs.push(log)

      // 如果缓冲区过大，立即刷新
      if (this.pendingLogs.length >= 50) {
        this.flushPendingLogs()
        return
      }

      // 否则延迟刷新（100ms内的日志批量添加）
      if (this._flushLogsTimer) {
        clearTimeout(this._flushLogsTimer)
      }

      this._flushLogsTimer = setTimeout(() => {
        this.flushPendingLogs()
      }, 100)
    },

    // 刷新待处理的日志到显示列表
    flushPendingLogs() {
      if (this.pendingLogs.length === 0) return

      // 批量添加日志
      this.outputLogs.push(...this.pendingLogs)

      // 限制日志数量，保留最新的 maxLogCount 条
      if (this.outputLogs.length > this.maxLogCount) {
        const removeCount = this.outputLogs.length - this.maxLogCount
        this.outputLogs.splice(0, removeCount)
      }

      // 清空缓冲区
      this.pendingLogs = []

      // 清除定时器
      if (this._flushLogsTimer) {
        clearTimeout(this._flushLogsTimer)
        this._flushLogsTimer = null
      }
    },

    // 刷新所有调试信息
    async refreshAll() {
      // 确保只在暂停状态下刷新
      if (this.debuggerState !== 'paused') {
        return
      }

      // 如果源文件列表为空，先加载（DAP 模式需要）
      if (this.sources.length === 0) {
        await this.loadSourceFiles()
      }

      await Promise.all([
        this.refreshStack(),
        this.refreshVariables(),
        this.refreshWatches(),
        this.refreshGoroutines()
      ])
    },

    // 添加 Watch 表达式
    async handleAddWatch(expression) {
      const watchId = Date.now()
      const newWatch = {
        id: watchId,
        expression: expression,
        loading: true,
        error: null,
        value: null,
        type: null,
        kind: null,
        children: []
      }

      this.watchExpressions.push(newWatch)

      // 如果调试器在暂停状态，立即求值
      if (this.debuggerState === 'paused') {
        await this.evaluateWatch(newWatch)
      }
    },

    // 删除 Watch 表达式
    handleRemoveWatch(id) {
      this.watchExpressions = this.watchExpressions.filter(w => w.id !== id)
    },

    // 刷新所有 Watch 表达式
    async refreshWatches() {
      if (this.debuggerState !== 'paused') {
        console.log('[Watch] 跳过刷新: debuggerState =', this.debuggerState)
        return
      }
      if (this.watchExpressions.length === 0) {
        console.log('[Watch] 跳过刷新: 无 watch 表达式')
        return
      }

      console.log('[Watch] 开始刷新', this.watchExpressions.length, '个表达式')
      this.watchLoading = true
      try {
        await Promise.all(
          this.watchExpressions.map(watch => this.evaluateWatch(watch))
        )
        console.log('[Watch] 刷新完成')
        // 强制更新以确保所有 watch 表达式都能正确显示
        this.$forceUpdate()
      } finally {
        this.watchLoading = false
      }
    },

    // 求值单个 Watch 表达式
    async evaluateWatch(watch) {
      console.log('[Watch] 求值:', watch.expression)
      this.$set(watch, 'loading', true)
      this.$set(watch, 'error', null)

      try {
        // 使用与局部变量相同的深度配置
        const result = await debuggerApi.evaluate(watch.expression, this.localVariableDepth)
        console.log('[Watch] 结果:', watch.expression, '=', result.success ? result.variable.value : result.message)
        if (result.success && result.variable) {
          // 使用 Vue.set 批量更新所有属性
          this.$set(watch, 'value', result.variable.value)
          this.$set(watch, 'type', result.variable.type)
          this.$set(watch, 'kind', result.variable.kind)
          this.$set(watch, 'len', result.variable.len)
          this.$set(watch, 'addr', result.variable.addr)
          this.$set(watch, 'children', result.variable.children || [])
          this.$set(watch, 'error', null)
        } else {
          this.$set(watch, 'error', result.message || '求值失败')
        }
      } catch (error) {
        console.error('[Watch] 错误:', watch.expression, error)
        this.$set(watch, 'error', error.message)
      } finally {
        this.$set(watch, 'loading', false)
      }
    },

    // 刷新 Goroutine 列表
    async refreshGoroutines() {
      if (this.debuggerState !== 'paused') {
        return
      }

      this.goroutinesLoading = true
      try {
        const result = await debuggerApi.listGoroutines()
        if (result.success) {
          this.goroutines = result.goroutines
        } else {
          console.error('[DebuggerView] 获取 Goroutine 列表失败:', result.message)
        }
      } catch (error) {
        console.error('[DebuggerView] 获取 Goroutine 列表异常：', error)
      } finally {
        this.goroutinesLoading = false
      }
    },

    // 选择 Goroutine
    async handleSelectGoroutine(goroutine) {
      this.selectedGoroutineId = goroutine.id
      this.$message.info(`已切换到 Goroutine ${goroutine.id}`)

      // 切换到该 Goroutine 的堆栈和变量
      await this.switchToGoroutine(goroutine.id)
    },

    // 切换到指定 Goroutine
    async switchToGoroutine(goroutineID) {
      if (this.debuggerState !== 'paused') {
        return
      }

      // 设置 loading 状态
      this.stackLoading = true
      this.variablesLoading = true

      try {
        // 并行获取该 Goroutine 的堆栈和变量（使用配置的深度）
        const [stackResult, localResult] = await Promise.all([
          debuggerApi.getStacktrace(50, goroutineID),
          debuggerApi.getLocalVariables(goroutineID, 0, this.localVariableDepth)
        ])

        // 更新堆栈
        if (stackResult.success) {
          this.stackFrames = stackResult.frames
        }

        // 更新局部变量
        if (localResult.success) {
          this.localVariables = localResult.variables
        } else {
          // 如果是 "unable to find function context" 错误，不显示错误
          if (!localResult.message.includes('unable to find function context')) {
            console.error('[DebuggerView] 获取局部变量失败:', localResult.message)
          }
          this.localVariables = []
        }

        // 更新当前 goroutine ID
        this.currentGoroutineId = goroutineID
      } catch (error) {
        console.error('[DebuggerView] 切换 Goroutine 失败:', error)
        this.$message.error(`切换 Goroutine 失败: ${error.message}`)
      } finally {
        this.stackLoading = false
        this.variablesLoading = false
      }
    },

    // 清空调试信息（不包括输出日志）
    clearDebugInfo() {
      this.stackFrames = []
      this.localVariables = []
      this.goroutines = []
      this.selectedGoroutineId = null
      // 注意：不清空 outputLogs，保留日志供查看
    },

    // 加载源文件列表
    async loadSourceFiles() {
      this.sourcesLoading = true
      try {
        const result = await debuggerApi.listSources('')
        if (result.success) {
          // 智能过滤：只保留用户项目的 .go 文件
          this.sources = result.sources.filter(s => {
            // 必须是 .go 文件
            if (!s.endsWith('.go')) return false

            // 排除 Go 标准库和常见第三方依赖
            const excludePatterns = [
              '/go/src/',           // Go 标准库根目录
              '\\go\\src\\',        // Windows 路径
              '/usr/lib/go',        // Linux 系统 Go 安装路径
              '/usr/local/go',      // Linux 自定义 Go 安装路径
              'C:\\Go\\',           // Windows Go 安装路径
              '/pkg/mod/',          // Go modules 缓存路径
              '\\pkg\\mod\\',       // Windows modules 路径
              '/vendor/',           // vendor 目录
              '\\vendor\\',         // Windows vendor 路径
              '@v',                 // Go modules 版本标识
              '/runtime/',          // Go runtime
              '\\runtime\\',
              '/internal/',         // Go internal 包 (通常是标准库)
              '<autogenerated>',    // 自动生成的代码
              '_test.go'            // 测试文件（可选）
            ]

            // 检查是否匹配排除模式
            for (const pattern of excludePatterns) {
              if (s.includes(pattern)) {
                return false
              }
            }

            return true
          })

          // 按路径排序，方便查找
          this.sources.sort((a, b) => a.localeCompare(b))
        } else {
          console.error('获取源文件列表失败：', result.message)
        }
      } catch (error) {
        console.error('获取源文件列表失败：', error)
      } finally {
        this.sourcesLoading = false
      }
    },

    // 恢复断点
    async restoreBreakpoints() {
      if (this.breakpoints.length === 0) {
        return
      }

      const successCount = []
      const failedCount = []

      for (const bp of this.breakpoints) {
        // 初始化 hitCount（如果不存在）
        if (typeof bp.hitCount === 'undefined') {
          bp.hitCount = 0
        }

        // 只恢复启用的断点
        if (bp.enabled === false) {
          bp.dlvId = null // 禁用的断点不设置到dlv
          continue
        }

        try {
          const result = await debuggerApi.setBreakpoint(bp.file, bp.line, bp.condition, bp.hitCondition)
          if (result.success) {
            // 更新断点的dlvId
            bp.dlvId = result.breakpoint.dlvId
            successCount.push(bp)
          } else {
            failedCount.push(bp)
          }
        } catch (error) {
          failedCount.push(bp)
        }
      }

      if (successCount.length > 0) {
        this.$message.success(`已恢复 ${successCount.length} 个断点`)
      }
      if (failedCount.length > 0) {
        this.$message.warning(`${failedCount.length} 个断点恢复失败`)
      }
    },

    // 设置调试器事件监听
    setupDebuggerListeners() {
      debuggerApi.onOutput((data) => {
        this.addLog({
          type: data.type,
          content: data.data,
          timestamp: new Date()
        })
      })

      debuggerApi.onError((data) => {
        this.addLog({
          type: 'error',
          content: data.message,
          timestamp: new Date()
        })
        this.$message.error(data.message)
      })

      debuggerApi.onExit((data) => {
        this.debuggerState = 'stopped'
        this.addLog({
          type: 'info',
          content: `调试器已退出，代码：${data.code}`,
          timestamp: new Date()
        })
        this.$message.info('调试器已退出')
      })

      debuggerApi.onBreakpointHit(async (data) => {
        console.log('[BreakpointHit] 断点命中事件触发')
        this.debuggerState = 'paused'

        // 保存当前 goroutine ID
        if (data.goroutineID) {
          this.currentGoroutineId = data.goroutineID
        } else if (data.state && data.state.currentGoroutine) {
          this.currentGoroutineId = data.state.currentGoroutine.id
        }

        // 更新断点命中统计
        if (data.state && data.state.currentThread && data.state.currentThread.breakpoint) {
          const hitBreakpointId = data.state.currentThread.breakpoint.id
          const breakpoint = this.breakpoints.find(bp => bp.dlvId === hitBreakpointId)
          if (breakpoint) {
            breakpoint.hitCount = (breakpoint.hitCount || 0) + 1
            this.$message.info(`命中断点（第 ${breakpoint.hitCount} 次）`)
          } else {
            this.$message.info('命中断点')
          }
        } else {
          this.$message.info('命中断点')
        }

        // 等待一小段时间，确保 dlv 状态完全同步
        await new Promise(resolve => setTimeout(resolve, 100))

        // 再次检查状态，防止在延迟期间用户点击了 Continue
        if (this.debuggerState !== 'paused') {
          console.log('[BreakpointHit] 状态已变化，取消刷新')
          return
        }

        // 自动刷新调试信息
        console.log('[BreakpointHit] 开始刷新调试信息')
        await this.refreshAll()
        console.log('[BreakpointHit] 调试信息刷新完成')
      })

      // 监听程序退出
      debuggerApi.onProgramExited((data) => {
        this.debuggerState = 'stopped'
        this.addLog({
          type: 'info',
          content: `程序已退出，退出状态：${data.exitStatus || 0}`,
          timestamp: new Date()
        })
        this.$message.success('程序执行完成')
        this.clearDebugInfo()
      })
    },

    // 设置事件监听（来自App.vue的事件）
    setupEventListeners() {
      // 监听从历史记录加载程序
      this.$root.$on('load-program', this.handleLoadProgram)
      // 监听从历史记录启动调试
      this.$root.$on('debug-program', this.handleDebugProgramFromHistory)
    },

    // 处理从历史记录加载程序
    handleLoadProgram(data) {
      if (this.debuggerState !== 'stopped') {
        this.$message.warning('请先停止当前调试会话')
        return
      }

      // 支持旧格式（字符串）和新格式（对象）
      if (typeof data === 'string') {
        this.programPath = data
        this.$message.success('已加载程序：' + this.extractProgramName(data))
      } else {
        this.programPath = data.path
        // 恢复断点列表（确保每个断点都有 dlvId 和 hitCount 字段）
        if (data.breakpoints && data.breakpoints.length > 0) {
          this.breakpoints = data.breakpoints.map(bp => ({
            ...bp,
            dlvId: null, // 标记为未设置到dlv，将在启动时恢复
            hitCount: 0 // 初始化命中次数
          }))
          this.$message.success(`已加载程序及 ${data.breakpoints.length} 个断点：` + this.extractProgramName(data.path))
        } else {
          this.breakpoints = []
          this.$message.success('已加载程序：' + this.extractProgramName(data.path))
        }
      }
    },

    // 处理从历史记录启动调试
    async handleDebugProgramFromHistory(data) {
      if (this.debuggerState !== 'stopped') {
        this.$message.warning('请先停止当前调试会话')
        return
      }

      // 支持旧格式（字符串）和新格式（对象）
      if (typeof data === 'string') {
        this.programPath = data
      } else {
        this.programPath = data.path
        // 恢复断点列表
        if (data.breakpoints && data.breakpoints.length > 0) {
          this.breakpoints = data.breakpoints.map(bp => ({
            ...bp,
            dlvId: null, // 标记为未设置到dlv，将在启动时恢复
            hitCount: 0 // 初始化命中次数
          }))
        } else {
          this.breakpoints = []
        }
      }

      // 稍微延迟启动，确保页面切换完成
      await this.$nextTick()
      await this.handleStart()
    },

    // 设置变量值
    async setVariableValue(symbol, value, goroutineID, frameIndex) {
      try {
        const result = await debuggerApi.setVariable(symbol, value, goroutineID, frameIndex)
        if (result.success) {
          // 刷新变量列表以显示最新值
          await this.refreshVariables()
        }
        return result
      } catch (error) {
        console.error('[DebuggerView] 设置变量值失败：', error)
        return { success: false, message: error.message }
      }
    },

    // 面板调整大小
    startResize(panel, event) {
      this.resizing = true
      this.resizePanel = panel
      const startX = event.clientX
      const startLeftWidth = parseInt(this.leftPanelWidth)
      const startRightWidth = parseInt(this.rightPanelWidth)

      const onMouseMove = (e) => {
        if (!this.resizing) return

        const deltaX = e.clientX - startX

        if (panel === 'left') {
          const newWidth = Math.max(250, Math.min(600, startLeftWidth + deltaX))
          this.leftPanelWidth = newWidth + 'px'
        } else {
          const newWidth = Math.max(250, Math.min(600, startRightWidth - deltaX))
          this.rightPanelWidth = newWidth + 'px'
        }
      }

      const onMouseUp = () => {
        this.resizing = false
        this.resizePanel = null
        document.removeEventListener('mousemove', onMouseMove)
        document.removeEventListener('mouseup', onMouseUp)
        document.body.style.cursor = ''
        document.body.style.userSelect = ''
      }

      document.addEventListener('mousemove', onMouseMove)
      document.addEventListener('mouseup', onMouseUp)
      document.body.style.cursor = 'col-resize'
      document.body.style.userSelect = 'none'
    }
  }
}
</script>

<style scoped>
/* Element UI Tabs 样式定制 */
.side-tabs >>> .el-tabs__header {
  background-color: #ffffff;
  margin: 0;
  border-bottom: 1px solid #e5e7eb;
  padding: 0 12px;
}

.side-tabs >>> .el-tabs__item {
  color: #6b7280;
  font-size: 13px;
  height: 44px;
  line-height: 44px;
}

.side-tabs >>> .el-tabs__item.is-active {
  color: #0070f3;
  font-weight: 500;
}

.side-tabs >>> .el-tabs__active-bar {
  background-color: #0070f3;
}

.side-tabs >>> .el-tabs__content {
  height: calc(100% - 45px);
  overflow: hidden;
}

.side-tabs >>> .el-tab-pane {
  height: 100%;
}
</style>
